<?php
/**
 * BootAdmin is committed to providing solutions for quickly building web applications
 * Please view the LICENSE file that was distributed with this source code,
 * For the full copyright and license information.
 * Thank you very much for using BootAdmin.
 *
 * @Author G.r<root@BootAdmin.com>
 */

declare (strict_types=1);

namespace app\admin\model;

use app\common\model\BaseModel;
use think\model\concern\SoftDelete;

/**
 * 菜单模型
 */
class Menu extends BaseModel
{
    // 定义软删除
    use SoftDelete;

    /**
     * 类型
     */
    public const LINK = 'L';
    public const IFRAME = 'I';
    public const MENUS_LIST = 'M';
    public const BUTTON = 'B';

    protected array $allowModifyFields = ['sort', 'status'];

    protected array $fields = ['id', 'parent_id', 'id' => 'value', 'name' => 'label'];

    /**
     * 初始化
     */
    public function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub
        $this->query->order('sort', 'desc');
    }

    /**
     * 获取列表
     */
    public function getList(bool $onlyTrashed = false)
    {
        if (!isset($this->params['onlyMenu'])) {
            $this->query->where('type', '=', self::MENUS_LIST);
        }
        return parent::getList($onlyTrashed); // TODO: Change the autogenerated stub
    }

    /**
     * 新增
     * @return bool
     */
    public function add(): bool
    {
        $this->setParams($this->handleData($this->params));
        return parent::add(); // TODO: Change the autogenerated stub
    }

    public function edit($id): bool
    {
        $this->setParams($this->handleData($this->params));
        return parent::edit($id); // TODO: Change the autogenerated stub
    }

    /**
     * 处理数据
     * @param $data
     * @return array
     */
    public function handleData($data): array
    {
        if (empty($data['parent_id']) || $data['parent_id'] == 0) {
            $data['level'] = '0';
            $data['parent_id'] = 0;
            $data['type'] = $data['type'] === self::BUTTON ? self::MENUS_LIST : $data['type'];
        } else {
            $parentMenu = $this->find((int) $data['parent_id']);
            $data['level'] = $parentMenu['level'] . ',' . $parentMenu['id'];
        }
        return $data;
    }

    /**
     * 生成按钮菜单
     */
    public function genButtonMenu($model)
    {
        $buttonMenus = [
            ['name' => $model['name'].'列表', 'code' => $model['code'].':index'],
            ['name' => $model['name'].'回收站', 'code' => $model['code'].':recycle'],
            ['name' => $model['name'].'保存', 'code' => $model['code'].':add'],
            ['name' => $model['name'].'更新', 'code' => $model['code'].':edit'],
            ['name' => $model['name'].'删除', 'code' => $model['code'].':delete'],
            ['name' => $model['name'].'读取', 'code' => $model['code'].':read'],
            ['name' => $model['name'].'属性修改', 'code' => $model['code'].':modify'],
            ['name' => $model['name'].'恢复', 'code' => $model['code'].':recovery'],
            ['name' => $model['name'].'真实删除', 'code' => $model['code'].':realDel'],
            ['name' => $model['name'].'快捷列表', 'code' => $model['code'].':getList']
        ];

        foreach ($buttonMenus as $button) {
            (new static())->save($this->handleData(array_merge(
                ['parent_id' => $this->id, 'type' => self::BUTTON],
                $button
            )));
        }
        return true;
    }

    /**
     * 系统菜单转前端路由树
     * @return array
     */
    public function sysMenuToRouterTree($data): array
    {
        if (empty($data)) return [];

        $routers = [];
        foreach ($data as $menu) {
            array_push($routers, $this->setRouter($menu));
        }
        return $this->toTree($routers);
    }

    /**
     * @param $menu
     * @return array
     */
    public function setRouter(&$menu): array
    {
        $route = ($menu['type'] == 'L' || $menu['type'] == 'I') ? $menu['route'] : '/' . $menu['route'];
        return [
            'id' => $menu['id'],
            'parent_id' => $menu['parent_id'],
            'name' => $menu['code'],
            'component' => $menu['component'],
            'path' => $route,
            'redirect' => $menu['redirect'],
            'meta' => [
                'type'   => $menu['type'],
                'icon'   => $menu['icon'],
                'title'  => $menu['name'],
                'hidden' => ($menu['is_hidden'] === 1),
                'hiddenBreadcrumb' => false
            ]
        ];
    }

    /**
     * @param array $data
     * @param int $parentId
     * @param string $id
     * @param string $parentField
     * @param string $children
     * @return array
     */
    public function toTree(array $data = [], int $parentId = 0, string $id = 'id', string $parentField = 'parent_id', string $children='children'): array
    {
        $data = $data ?: $this->toArray();

        if (empty($data)) return [];

        $tree = [];

        foreach ($data as $value) {
            if ($value[$parentField] == $parentId) {
                $child = $this->toTree($data, $value[$id], $id, $parentField, $children);
                if (!empty($child)) {
                    $value[$children] = $child;
                }
                array_push($tree, $value);
            }
        }

        unset($data);
        return $tree;
    }

    /**
     * 关联角色表
     */
    public function roles()
    {
        return $this->belongsToMany(Role::class, 'role_menu', 'role_id', 'menu_id');
    }
}